home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / pointers.swg / 0048_BTREE Unit.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1997-08-30  |  21.0 KB  |  748 lines

  1.  
  2. Unit bTree; { Zak's Binary Tree Object / routines.. }
  3.  
  4. {$O+,F+} { allow overlays }
  5.  
  6. Interface
  7. Type KeyType = String[35]; {This can be changed if needed .., int, word, etc}
  8.  
  9. Type StatusType = (Used,Free);
  10. Type ShowAllFuncType = Function (k:keytype;var Data):boolean;
  11.  
  12.  LeafType = record    { A "living" leaf }
  13.       Status: StatusType;        { Status of node .. unused but useful } 
  14.       Mother,Left,Right:longint; { pointers to Parent, Left, and Right nodes }
  15.       Key: KeyType;              { the keyed data }
  16.      end;
  17.  GenericProcedure = procedure;   { used to dispay balancing status }
  18.  
  19.  FileHeaderType = record      
  20.       DataRecSize,               { size of data records }
  21.       Root,                      { pointer to root node }
  22.       NextFree: longint;         { next free, unused node }
  23.      end;
  24.  
  25.  DirectionType = (Right,Left);   { the directions, duh }
  26.  
  27.  DeletedLeaf = record            { a "dead" leaf -- overlaps old LeafType }
  28.       Status  : StatusType;      { node status, hopefully Free}
  29.       NextFree: longint;         { pointer to next unused, free node }
  30.       Filler  : array[1..2]
  31.                   of longint;    { pad LeafType.Left and Right }
  32.       Filler2 : KeyType;         { pad LeafType.Key }
  33.       end;
  34.  
  35.  pbTreeObj = ^bTreeObj;
  36.  bTreeObj = Object
  37.  
  38.   Constructor Init       ( filename:string ; DataRecSize_:longint );
  39.  
  40.      { Initialize the object.. DataRecSize_ is ignored if the file is not
  41.        new (has been Init'd before)}
  42.  
  43.   Destructor Done;
  44.  
  45.      { unused the memory and close the file }
  46.  
  47.   Function  Add          (Key: keytype; Var Data):boolean;
  48.  
  49.      { Add Data by Key -- returns FALSE if key exists, otherwise TRUE }
  50.  
  51.   Function  Find         (key: keytype):boolean;
  52.  
  53.      { returns TRUE if key could be found, FALSE otherwise }
  54.  
  55.   Function  FindData     (key: keytype; var data):boolean;
  56.  
  57.      { if key is found, then returns TRUE and correct data, FALSE otherwise }
  58.  
  59.   Function  Delete       (key: keytype):boolean;
  60.  
  61.      { returns TRUE if successful, FALSE if key not found }
  62.  
  63.   Function  BalanceHeapReq:longint;
  64.  
  65.      { returns bytes of heap required for a Balance }
  66.  
  67.   Procedure Balance      (Reading,Sorting,Updating:GenericProcedure);
  68.  
  69.      { Makes the AVERAGE number of links needed to find a key the least
  70.        possible }
  71.  
  72.   Procedure ShowAll (func:ShowAllFuncType);
  73.  
  74.      { cycles through all the nodes, calling func until it returns FALSE 
  75.        or no more nodes.. }
  76.  
  77.   function Update(key:keytype; Var Data):boolean;
  78.  
  79.      { if key found, writes new Data to it, otherwise returns FALSE }
  80.  
  81.   private { INTERNAL to the object }
  82.    f:file;                  { the file we're playing with }
  83.    dataRecSize:longint;     { current data record size }
  84.    Function RecOfs        (n:longint):longint;
  85.       { returns offset of given record }
  86.    Procedure ReadRecLeaf  (n:longint;var RecHdr:LeafType);
  87.       { reads only the LeafType of record n }
  88.    Procedure ReadRecBoth  (n:longint;var RecHdr:LeafType;var data);
  89.       { reads both the LeafType and the data }
  90.    Procedure WriteRecLeaf (n:longint;RecHdr:LeafType);
  91.       { writes only the LeafType}
  92.    Procedure WriteRecBoth (n:longint;RecHdr:LeafType;var data);
  93.       { write both the LeafType and Data }
  94.    Procedure WriteRecData (n:longint;var data);
  95.       { just write the data for record n }
  96.    Function  NumRecords   (filehdr:fileheadertype):longint;
  97.       { returns number of total records in file }
  98.    Function  GetNewRecNum (filehdr:fileheadertype):longint;
  99.       { returns next free record number }
  100.    Procedure ReadFileHdr  (var filehdr:fileheadertype);
  101.       { reads the file header .. cryptic, eh? }
  102.    Procedure WriteFileHdr (filehdr:fileheadertype);
  103.       { writes the file's header }
  104.    Procedure FindNewMother(r:longint;filehdr:fileheadertype);
  105.       { reassign this node a new, more suitable, parent when orphaned :-) }
  106.    Function  FindKeyRec   (key: keytype):longint;
  107.       { returns record number with this key, 0 otherwise }
  108.   end;
  109.  
  110. Implementation
  111. uses Dos;
  112.  
  113. Constructor bTreeObj.Init( filename:string; datarecsize_:longint );
  114.  var fileheader:fileheadertype;
  115.   t:word;
  116.  begin
  117.  {$I-}
  118.  assign(f,filename);
  119.  reset(f,1);
  120.  {$I+}
  121.  t:=ioresult;
  122.  Case t of
  123.   0: begin { file exists.. ok so far }
  124.      ReadFileHdr(fileheader);
  125.      datarecsize:=fileheader.datarecsize;  { init. prv. datarecsize }
  126.      end;
  127.   2: begin { new file, let's initialize it, ok? }
  128.      ReWrite(f,1);
  129.      FileHeader.DataRecSize:=DataRecSize_; { setup header data }
  130.      datarecsize:=datarecsize_;
  131.      FileHeader.Root:=0;
  132.      FileHeader.NextFree:=0;
  133.      BlockWrite(f,FileHeader,Sizeof(FileHeader)) { write header data }
  134.      end
  135.   else RunError(t); { some other error .. }
  136.   end
  137.  end;
  138.  
  139. Procedure bTreeObj.ShowAll (func:ShowAllFuncType);
  140.  var fileheader:fileheadertype;
  141.      rh     :leaftype;
  142.      data   :pointer;
  143.      cont   :boolean;
  144.  procedure climb(r:longint);
  145.       var right:longint;
  146.       begin
  147.       ReadRecboth(r,rh,Data^);
  148.       right:=rh.right;
  149.       if not(rh.left=0) then
  150.          begin
  151.          Climb(rh.left);
  152.          ReadRecBoth(r,rh,data^) { read back current data if needed }
  153.          end;
  154.       if not cont then exit; { "just checking" }
  155.       cont := func(rh.key,data^);
  156.       if not cont then exit;
  157.       if not(right=0) then Climb(right);
  158.       end;
  159.  begin
  160.  cont := true;
  161.  ReadFileHdr(fileheader);
  162.  GetMem(data,fileheader.datarecsize);
  163.  if fileheader.root<>0 then Climb(fileheader.root);
  164.  FreeMem(data,fileheader.datarecsize);
  165.  end;
  166.  
  167.  
  168. Destructor bTreeObj.Done;
  169.   begin
  170.   close(f) { just close the file.. no big deal }
  171.   end;
  172.  
  173. Function  bTreeObj.Add(Key: keytype; var data):boolean;
  174.   var FileHdr: FileHeaderType;
  175.       RecHdr  : LeafType;
  176.   Procedure AddNewRec;
  177.     Function FindMother(var direction:directiontype):longint;
  178.       var RecHdr  :leaftype;
  179.           LastNode:longint;
  180.       procedure Search_Tree(n:longint);
  181.         begin
  182.         ReadRecLeaf(n,RecHdr);
  183.         if Key>RecHdr.Key then
  184.              if not(RecHdr.Right=0) then Search_Tree(RecHdr.Right) else
  185.                  begin
  186.                  LastNode:=n;
  187.                  Direction:=Right;
  188.                  end
  189.         else if Key<RecHdr.Key then
  190.              if not(RecHdr.Left=0) then Search_Tree(RecHdr.Left) else
  191.                  begin
  192.                  LastNode:=n;
  193.                  Direction:=left;
  194.                  end;
  195.         end;
  196.       begin
  197.       Search_Tree(filehdr.root);
  198.       FindMother:=LastNode;
  199.       end;
  200.     var MotherRec      :longint;
  201.         MotherRecHdr   :Leaftype;
  202.         MotherDirection:directiontype;
  203.         NewRecNum      :longint;
  204.         NewRecHdr      :leaftype;
  205.     begin
  206.     MotherRec:=FindMother(MotherDirection); { find available mother node }
  207.     ReadRecLeaf(MotherRec,MotherRecHdr);    { "read her data" }
  208.     NewRecNum := GetNewRecNum(filehdr);     { get next free record number }
  209.     if not(NewRecNum>NumRecords(filehdr)) then
  210.       begin
  211.       ReadRecLeaf(NewRecNum,NewRecHdr);
  212.       FileHdr.NextFree:=DeletedLeaf(NewRecHdr).NextFree;
  213.       end;
  214.     Case MotherDirection of
  215.        Right: MotherRecHdr.Right:=NewRecNum;
  216.        Left : MotherRecHdr.Left :=NewRecNum;
  217.        end;
  218.     With NewRecHdr do { initialize record.. }
  219.       begin
  220.       Status := used;
  221.       Right  := 0;
  222.       Left   := 0;
  223.       Mother := MotherRec;
  224.       end;
  225.     NewRecHdr.Key:=Key;
  226.     WriteFileHdr(FileHdr);                  { update file header }
  227.     WriteRecLeaf(MotherRec,MotherRecHdr);   { write mother }
  228.     WriteRecBoth(newrecnum,NewRecHdr,Data); { write daughter }
  229.     end;
  230.   procedure AddFirstRec;
  231.     begin { we're adding the first record in the file.. scary eh? }
  232.     With RecHdr do { init. it }
  233.       begin
  234.       Status := Used;
  235.       Right  := 0;
  236.       Left   := 0;
  237.       Mother := 0;
  238.       end;
  239.     RecHdr.key:=key;
  240.     FileHdr.Root := 1;
  241.     FileHdr.NextFree := 0;
  242.     Seek(f,0);
  243.     BlockWrite(f,Filehdr,sizeof(filehdr));
  244.     BlockWrite(f,RecHdr,Sizeof(RecHdr));
  245.     BlockWrite(f,data,filehdr.datarecsize);
  246.     end;
  247.   begin
  248.   if not Find(key) then { if not found, then .. }
  249.     begin
  250.     ReadFileHdr(filehdr);
  251.     if FileHdr.Root=0 then
  252.        AddFirstRec
  253.     else
  254.        AddNewRec;
  255.     add := true;
  256.     end
  257.   else Add := false;
  258.   end;
  259.  
  260. Function  bTreeObj.Find     (key: keytype):boolean;
  261.  begin
  262.  Find:=FindKeyRec(key)>0; { or BOOLEAN(FindKey(key)) would work too }
  263.  end;
  264.  
  265. Function bTreeObj.Update(key:keytype; Var Data):boolean;
  266.  var i:longint;
  267.  begin
  268.  i:=FindKeyRec(key);
  269.  if i=0 then
  270.    begin
  271.    Update:=False;
  272.    end
  273.  else
  274.    begin
  275.    WriteRecData(i,data);
  276.    update:=true;
  277.    end
  278.  end;
  279.  
  280. Function  bTreeObj.FindData    (key: keytype; var data):boolean;
  281.  var filehdr:fileheadertype;
  282.      rechdr :leaftype;
  283.      r      :longint;
  284.  begin
  285.  r:=FindKeyRec(key);
  286.  if r>0 then
  287.    begin
  288.    ReadRecBoth(r,rechdr,data);
  289.    FindData:=true;
  290.    end
  291.  else
  292.    finddata:=false
  293.  end;
  294.  
  295. Function bTreeObj.Delete(key: keytype):boolean;
  296.  var filehdr:fileheadertype;
  297.  procedure Unlink(r:longint;var delhdr:leaftype);
  298.   Function GetDirection(sonhdr:leaftype):directiontype;
  299.    var sonrighthdr,sonlefthdr,motherhdr:leaftype;
  300.        sre,sle:boolean;
  301.    begin
  302.    ReadRecLeaf(sonhdr.mother,motherhdr);
  303.    if not(motherhdr.left=0) then
  304.      begin
  305.      ReadRecLeaf(motherhdr.left,sonlefthdr);
  306.      sle:=true
  307.      end
  308.      else sle:=false;
  309.    if not(motherhdr.right=0) then
  310.      begin
  311.      ReadRecLeaf(motherhdr.right,sonrighthdr);
  312.      sre:=true;
  313.      end
  314.      else sre:=false;
  315.    {$B-}
  316.    if      sle and not sre then GetDirection:=Left
  317.    else if sre and not sle then GetDirection:=Right
  318.    else if (sle and sre) and (sonrighthdr.key=sonhdr.key) then GetDirection:=Right
  319.    else if (sle and sre) and (sonlefthdr.key=sonhdr.key) then GetDirection:=left;
  320.    {$B+}
  321.    end;
  322.  
  323.    var MotherHdr:leaftype;
  324.        direction:directiontype;
  325.    begin
  326.    if not(DelHdr.Mother=0) then
  327.      begin
  328.      ReadRecLeaf(DelHdr.Mother,MotherHdr);
  329.      Direction:=GetDirection(DelHdr);
  330.      case Direction Of
  331.        Left : MotherHdr.Left:=0;
  332.        Right: MotherHdr.Right:=0;
  333.        end;
  334.      WriteRecLeaf(delhdr.mother,motherhdr);
  335.      end
  336.    end;
  337.  
  338.  Procedure UpdateFreeList(r:longint);
  339.    function LastFree:longint;
  340.     var rechdr:leaftype;n,ths:longint;
  341.      begin
  342.      n:=filehdr.nextfree;
  343.      ths:=n;
  344.      repeat
  345.        begin
  346.        ReadRecLeaf(n,rechdr);
  347.        ths:=n;
  348.        n:=deletedleaf(rechdr).nextfree;
  349.        end
  350.      until DeletedLeaf(RecHdr).nextfree=0;
  351.      LastFree:=ths;
  352.      end;
  353.  
  354.    Var updatedptrhdr:leaftype;lf:longint;
  355.    begin
  356.    if filehdr.nextfree=0 then
  357.      begin
  358.      filehdr.nextfree:=r;
  359.      writefilehdr(filehdr);
  360.      end
  361.    else
  362.      begin
  363.      lf:=lastfree;
  364.      ReadRecLeaf(Lf,updatedptrhdr);
  365.      DeletedLeaf(updatedptrhdr).nextfree:=r;
  366.      WriteRecLeaf(lf,updatedptrhdr);
  367.      end;
  368.    end;
  369.  
  370.  Procedure AddChildren(var dhdr:leaftype);
  371.    begin
  372.    if not(dhdr.left=0) then FindNewMother(dhdr.left,filehdr);
  373.    if not(dhdr.right=0) then FindNewMother(dhdr.right,filehdr);
  374.    end;
  375.  
  376.  Procedure ChangeMother(r,tor:longint);
  377.   var rechdr:leaftype;
  378.   begin
  379.   ReadRecLeaf(r,rechdr);
  380.   rechdr.mother:=tor;
  381.   WriteRecLeaf(r,rechdr);
  382.   end;
  383.  
  384.  { this is huge }
  385.  
  386.  var DelRecNum:longint;
  387.      delhdr   :leaftype;
  388.  begin
  389.  ReadFileHdr(filehdr);
  390.  DelRecNum:=FindKeyRec(key); { find the record we're refering to }
  391.  DelHdr.Status:=Free; { change its status }
  392.  if not(DelRecNum>0) then Delete:=False else
  393.   begin
  394.   ReadRecLeaf(delrecnum,delhdr); { read the dead-to-be's header }
  395.   if delhdr.Mother=0 then
  396.     { we're dealing with the ROOT node ! }
  397.     begin
  398.     Delete:=true;
  399.     UpdateFreeList(delrecnum); { add to free list }
  400.     if not(delhdr.Right=0) then
  401.       begin
  402.       FileHdr.Root := delhdr.Right;
  403.       ChangeMother(delhdr.Right,0);
  404.       if not(delhdr.left=0) then FindNewMother(delhdr.left,filehdr);
  405.       end;
  406.     if not(delhdr.left=0) and (delhdr.right=0) then
  407.       begin
  408.       FileHdr.Root := delhdr.Left;
  409.       ChangeMother(delhdr.Left,0);
  410.       end;
  411.     if (delhdr.right=0) and (delhdr.left=0) then
  412.       begin
  413.       FileHdr.Root:=0;
  414.       end;
  415.     DelHdr.Status:=Free;
  416.     WriteFileHdr(filehdr);
  417.     DeletedLeaf(DelHdr).NextFree:=0;
  418.     WriteRecLeaf(delrecnum,delhdr);
  419.     end
  420.   else
  421.     { the easy part }
  422.     begin
  423.     Delete:=true;
  424.     Unlink(DelRecNum,delhdr);         { unlink it from its parent }
  425.     UpdateFreeList(delrecnum);        { add to free list }
  426.     DeletedLeaf(DelHdr).NextFree:=0;  { this is the last in the chain .. }
  427.     WriteRecLeaf(delrecnum,delhdr);
  428.     AddChildren(delhdr);              { re-classify its offspring }
  429.     end;
  430.   end;
  431.  end;
  432.  
  433. Function  bTreeObj.BalanceHeapReq:longint;
  434.   var rechdr    :leaftype;
  435.       filehdr   :fileheadertype;
  436.       numnodes  :longint;
  437.    procedure Climb(r:longint);
  438.       begin
  439.       ReadRecLeaf(r,rechdr);
  440.       if not(rechdr.left=0) then Climb(rechdr.left);
  441.       ReadRecLeaf(r,rechdr);
  442.       inc(numnodes);
  443.       if not(rechdr.right=0) then Climb(rechdr.right);
  444.       end;
  445.    begin
  446.    numnodes:=0;
  447.    readfilehdr(filehdr);
  448.    if not(FileHdr.Root=0) then Climb(FileHdr.Root);
  449.    balanceheapreq:=numnodes*20; { sizeof(ListRecType) }
  450.    end;
  451.  
  452. Procedure bTreeObj.Balance(Reading,Sorting,Updating:GenericProcedure );
  453.  type ToListRecType = ^ListRecType;
  454.       ListRecType   = Record
  455.          node,mother,left,right:longint;
  456.          Next:ToListRecType;
  457.          end;
  458.  var filehdr     : fileheadertype;
  459.      ListRecRoot : ToListRecType;
  460.      NumNodes    : longint;
  461.      MarkMem     : pointer;
  462.  Procedure ReadFileToLL;
  463.   var rechdr    :leaftype;
  464.       curlistrec:tolistrectype;
  465.    Procedure Add(r:longint);
  466.      begin
  467.      inc(NumNodes);
  468.      if CurListRec=Nil then
  469.        begin
  470.        new(CurListRec);
  471.        CurListRec^.Next := Nil;
  472.        ListRecRoot := CurListRec;
  473.        end
  474.      else
  475.        begin
  476.        New(CurListRec^.next);
  477.        CurListRec:=CurListRec^.Next;
  478.        CurListRec^.Next := Nil;
  479.        end;
  480.      CurListRec^.Node:=r;
  481.      CurListRec^.Mother:=0;
  482.      CurListRec^.Left:=0;
  483.      CurListRec^.Right:=0;
  484.      end;
  485.    procedure Climb(r:longint);
  486.       begin
  487.       ReadRecLeaf(r,rechdr);
  488.       if not(rechdr.left=0) then Climb(rechdr.left);
  489.       ReadRecLeaf(r,rechdr);
  490.       Add(r);
  491.       if not(rechdr.right=0) then Climb(rechdr.right);
  492.       end;
  493.    begin
  494.    CurListRec:=ListRecRoot;
  495.    if not(FileHdr.Root=0) then Climb(FileHdr.Root);
  496.    end;
  497.  Procedure GetRecNumInfo(n:longint; var mother,left,right:longint);
  498.    var c:tolistrectype;
  499.    begin
  500.    c:=listrecroot;
  501.    while c^.node<>n do c:=c^.next;
  502.    mother:=c^.mother;
  503.    left:=c^.left;
  504.    right:=c^.right;
  505.    end;
  506.  Procedure PutRecNumInfo(n,mother,left,right:longint);
  507.   var c:tolistrectype;
  508.    begin
  509.    c:=listrecroot;
  510.    while c^.node<>n do c:=c^.next;
  511.    c^.mother:=mother;
  512.    c^.left:=left;
  513.    c^.right:=right;
  514.    end;
  515.  Function Power(b,e:longint):longint;
  516.    var t,c:longint;
  517.    begin
  518.    t:=b;
  519.    if e=0 then begin power:=1 ; exit end;
  520.    for c:=1 to e-1 do t:=t*b;
  521.    power:=t;
  522.    end;
  523.  Procedure ProcessLL;
  524.   var MaxNumNodes: longint;
  525.       NumSubLevels  : longint;
  526.       TempMother,TempRight,TempLeft:longint;
  527.       Modifier   : longint;
  528.   Function FindNumSubLevels(n:longint):longint;
  529.     var i:longint;
  530.     begin
  531.     i:=1;
  532.     repeat inc(i,1) until (power(2,i)>=n+1);
  533.     FindNumSubLevels:=i-1;
  534.     end;
  535.   Function RightMod(root,modi:longint):longint;
  536.     begin
  537.     repeat
  538.       begin
  539.       modi := modi div 2;
  540.       end
  541.     until root+modi<=numnodes;
  542.     RightMod := modi;
  543.     end;
  544.   Procedure FixSubTree(root:longint;mthr:longint);
  545.      var sr:longint;
  546.      begin
  547.      if not(abs(mthr-root)=1) then
  548.        begin
  549.        modifier:=abs(mthr-root) div 2;
  550.        templeft:=root-modifier;
  551.        if (root+modifier<=NumNodes) then
  552.           tempright:=root+modifier
  553.        else
  554.           begin
  555.           modifier:=Rightmod(root,modifier);
  556.           if not(modifier=0) then TempRight:=root+modifier else tempright:=0;
  557.           end;
  558.        tempmother:=mthr;
  559.        PutRecNumInfo(root,tempmother,templeft,tempright);
  560.        sr:=tempright;
  561.        if not(templeft=0) then FixSubTree(templeft,root);
  562.        if not(sr=0) then FixSubTree(sr,root);
  563.        end
  564.      else { lowest leaves }
  565.        begin
  566.        PutRecNumInfo(root,mthr,0,0);
  567.        end;
  568.      end;
  569.    Function MaxNodes:longint;
  570.     var i:longint;
  571.     begin
  572.     i:=0;
  573.     repeat inc(i,1) until (power(2,i+1)-1)>=NumNodes;
  574.     MaxNodes:= Power(2,i+1)-1;
  575.     end;
  576.   Var NewRoot:longint;
  577.   begin
  578.   MaxNumNodes := MaxNodes;
  579.   NumSubLevels := FindNumSubLevels(MaxNumNodes); { number of "shelves" }
  580.   if NumNodes<2 then NewRoot:=FileHdr.Root else NewRoot:=Power(2,NumSubLevels);
  581.   FileHdr.Root := NewRoot;
  582.   FixSubTree(NewRoot,0);
  583.   end;
  584.  Procedure WriteLLtoFile;
  585.    var CurListRec: tolistrectype;
  586.        l:leaftype;
  587.    begin
  588.    curlistrec:=listrecroot;
  589.    while curlistrec<>nil do
  590.       begin
  591.       ReadRecLeaf(curlistrec^.node,l);
  592.       l.left:=curlistrec^.left;
  593.       l.right:=curlistrec^.right;
  594.       l.mother:=curlistrec^.mother;
  595.       WriteRecLeaf(curlistrec^.node,l);
  596.       curlistrec:=curlistrec^.next;
  597.       end;
  598.    end;
  599.  begin
  600.  NumNodes := 0;
  601.  ListRecRoot:=nil;
  602.  Mark(MarkMem);
  603.  ReadFileHdr(filehdr);
  604.  reading; { status }
  605.  if not(filehdr.root=0) then ReadFileToLL; { if there are >0 records then }
  606.  sorting; { status }                       { read data into the linked list}
  607.  if not(filehdr.root=0) then ProcessLL;    { change data in LL }
  608.  updating; { status }
  609.  if not(filehdr.root=0) then WriteLLtoFile; { updated disk with LL data }
  610.  WriteFileHdr(filehdr);
  611.  Release(MarkMem);
  612.  end;
  613.  
  614. {privates}
  615.  
  616. Function bTreeObj.RecOfs(n:longint):longint;
  617.  begin
  618.  RecOfs:=Sizeof(FileHeaderType)+((n-1)*(DataRecSize+Sizeof(LeafType)));
  619.  end;
  620.  
  621. Procedure bTreeObj.ReadRecLeaf(n:longint;var RecHdr:LeafType);
  622.  begin
  623.  seek(f,recofs(n));
  624.  blockread(f,rechdr,sizeof(leaftype));
  625.  end;
  626.  
  627. Procedure bTreeObj.ReadRecBoth(n:longint;var RecHdr:LeafType;var data);
  628.  begin
  629.  seek(f,recofs(n));
  630.  blockread(f,rechdr,sizeof(rechdr));
  631.  blockread(f,data,datarecsize);
  632.  end;
  633.  
  634. Procedure bTreeObj.WriteRecLeaf(n:longint;RecHdr:LeafType);
  635.  begin
  636.  seek(f,recofs(n));
  637.  blockwrite(f,rechdr,sizeof(rechdr));
  638.  end;
  639.  
  640. Procedure bTreeObj.WriteRecBoth(n:longint;RecHdr:LeafType;var data);
  641.  begin
  642.  seek(f,recofs(n));
  643.  blockwrite(f,rechdr,sizeof(rechdr));
  644.  blockwrite(f,data,datarecsize);
  645.  end;
  646.  
  647. Procedure bTreeObj.WriteRecData (n:longint;var data);
  648.  begin
  649.  Seek(f,recofs(n)+Sizeof(LeafType));
  650.  blockwrite(f,data,datarecsize);
  651.  end;
  652.  
  653. Function bTreeObj.NumRecords(filehdr:fileheadertype):longint;
  654.  var tv:longint;
  655.  begin
  656.  NumRecords := (FileSize(f)-Sizeof(FileHdr)) div (Sizeof(LeafType)+FileHdr.DataRecSize);
  657.  end;
  658.  
  659. Function bTreeObj.GetNewRecNum(filehdr:fileheadertype):longint;
  660.  begin
  661.  if filehdr.nextfree=0 then
  662.   begin
  663.   GetNewRecNum := NumRecords(filehdr)+1;
  664.   exit
  665.   end
  666.  else
  667.   GetNewRecNum := FileHdr.NextFree;
  668.  end;
  669.  
  670. Procedure bTreeObj.ReadFileHdr(var filehdr:fileheadertype);
  671.  begin
  672.  seek(f,0);
  673.  blockread(f,FileHdr, sizeof(filehdr));
  674.  end;
  675.  
  676. Procedure bTreeObj.WriteFileHdr( filehdr:fileheadertype);
  677.  begin
  678.  seek(f,0);
  679.  blockwrite(f,FileHdr, sizeof(filehdr));
  680.  end;
  681.  
  682. Procedure bTreeObj.FindNewMother ( r:longint;filehdr:fileheadertype);
  683.     var rechdr:leaftype;
  684.     Function FindMother(var direction:directiontype):longint;
  685.       var Hdr  :leaftype;
  686.           LastNode:longint;
  687.       procedure Search_Tree(n:longint);
  688.         begin
  689.         ReadRecLeaf(n,Hdr);
  690.           if RecHdr.Key>Hdr.Key then
  691.              if not(Hdr.Right=0) then Search_Tree(Hdr.Right) else
  692.                  begin
  693.                  LastNode:=n;
  694.                  Direction:=Right;
  695.                  end
  696.           else if RecHdr.Key<Hdr.Key then
  697.              if not(Hdr.Left=0) then Search_Tree(Hdr.Left) else
  698.                  begin
  699.                  LastNode:=n;
  700.                  Direction:=left;
  701.                  end;
  702.         end;
  703.       begin
  704.       Search_Tree(filehdr.root);
  705.       FindMother:=LastNode;
  706.       end;
  707.  
  708.     var mhdr:leaftype;
  709.         mrec:longint;
  710.         motherdirection:directiontype;
  711.     begin
  712.     ReadRecLeaf(r,RecHdr);
  713.     mrec:=FindMother(motherdirection);
  714.     ReadRecLeaf(mrec,MHdr);
  715.     RecHdr.Mother := mrec;
  716.     Case MotherDirection of
  717.        Right: MHdr.Right:=r;
  718.        Left : MHdr.Left :=r;
  719.        end;
  720.     WriteRecLeaf(mrec,MHdr);
  721.     WriteRecLeaf(r,RecHdr);
  722.     end;
  723.  
  724. Function bTreeObj.FindKeyRec    (key: keytype):longint;
  725.  var filehdr:fileheadertype;
  726.      rechdr :leaftype;
  727.    procedure FindKey(r:longint);
  728.      begin
  729.      ReadRecLeaf(r,RecHdr);
  730.      if Key>RecHdr.Key then
  731.         if not(RecHdr.Right=0) then FindKey(RecHdr.Right) else
  732.                begin
  733.                FindKeyRec:=0;
  734.                end
  735.         else if Key<RecHdr.Key then
  736.              if not(RecHdr.Left=0) then FindKey(RecHdr.Left) else
  737.                begin
  738.                FindKeyRec:=0;
  739.                end
  740.         else if Key=RecHdr.Key then FindKeyRec:=r;
  741.      end;
  742.  begin
  743.  ReadFileHdr(filehdr);
  744.  if filehdr.root=0 then FindKeyRec:=0 else FindKey(filehdr.root)
  745.  end;
  746.  
  747. end.
  748.